/*
  CIVIC DASH
 Language: Wiring/Arduino
 
 
 Created 8 June. 2011
 by Jonathan Reeves
 
 
 This code is under GPLv3
 
 */

#include <LiquidCrystal.h>


#define rxPin 2
#define txPin 3

///////////////////States////////////////
#define ADRead 0
#define SerialRead 1
#define Scale 4
#define Display 5


/////////////serial states///////////////
#define WaterTempRead 0
#define IATRead 1
#define rpmHighRead 2
#define rpmLowRead 3
#define speedRead 4
#define o2Read 5
//////////////Display state//////////////
#define DisplayTemp 0
#define DisplayRpmSpeed 1
#define DisplayO2 2

////////////////////////////////////////
byte state=ADRead;
byte serialState=WaterTempRead;
byte displayState=4; 
////////////////////////////////////////
//Hardware setup varibles
LiquidCrystal LCD(12, 11, 5, 4, 3, 2);
int incoming = 0;
int sensorPin=0;
int  buttonPin = 7;

//Sensor and Serial Varibles
int VDOValue=0;

byte WaterTempRaw=0;
int WaterTemp=0;

byte IATRaw=0;
int IAT=0;

byte o2Raw=0;
float AFR=0;

unsigned int rpmHighRaw=0;
unsigned int rpmLowRaw=0;

unsigned int rpm=0;
unsigned int iirRpm=0;


byte speedRaw=0;
int  Speed=0;

unsigned int serialCount=0;

int buttonState=0;
int lastButtonState=0;
int buttonPush=0;


//int Time=0; //to see how fast it runs
//int lastTime=0;
//int lagTime=0;
//////////////////////////


void setup() {
  ///set button pin as input
  pinMode(buttonPin, INPUT);
  // define pin modes for tx, rx, led pins:
  pinMode(rxPin, INPUT);
  pinMode(txPin, OUTPUT);

  // set the data rate for the SoftwareSerial port
  LCD.begin(20,4);
  delay(10);

  Serial.begin(38400);
  //UCSR0C = UCSR0C | B00110000;///set odd parity


  delay(10);
  LCD.clear();

}

void loop() 
{

  switch (state){


    case(ADRead):      //Read analog and digital stuff so i can add my own sensors

    //Time=micros()-lastTime;


    VDOValue=analogRead(sensorPin);
    //Serial.println(VDO);
    state=SerialRead;


    buttonState = digitalRead(buttonPin);


    break;
    //////////////////////////////////////////////////////

    //    Start of serial stuff...sends a byte to the ecu and listens for a while then asks again
    //    if byte is recieved moves on to next sensor. 

    ///////////////////////////////////////////////////
    case(SerialRead):
    switch(serialState)
    {
      case(WaterTempRead):

      WaterTempRaw=ecuRead(SerialRead, IATRead,0x1D);

      break; 
      ///////////////////////////////////////
    case IATRead:

      IATRaw=ecuRead(SerialRead, rpmHighRead,0x1B);

      break;
      ////////////////////////////////////////////////////////

    case rpmHighRead:

      rpmHighRaw=ecuRead(SerialRead, rpmLowRead,0x11);

      break;
      ////////////////////////////////////////////////////////////
    case rpmLowRead:

      rpmLowRaw=ecuRead(SerialRead, speedRead,0x10);

      break;
      //////////////////////////////////////////////////////////      
    case speedRead:

      speedRaw=ecuRead(SerialRead,o2Read,0x1C);

      break;
   //////////////////////////////////////////////////////
    case o2Read:

      o2Raw=ecuRead(Scale,WaterTempRead,0x20);

      break;
    }

    break;
    ////////////////////////////////////////////////////
    //    
    //    Scaling stuff.  non linear temp sensors are approx by 
    //    linear regions.  
    //    
    /////////////////////////////////////////////////
    case(Scale):

//////scale Temps
    WaterTemp=calcTemp(WaterTempRaw);

    IAT=calcTemp(IATRaw);
    ///////////////////
    
    rpm=1875000/((rpmHighRaw * 256) + rpmLowRaw);
    iirRpm=.92*iirRpm+.08*rpm;
//////////////////////

    Speed=.4*speedRaw;
////////////////////////
//scale o2 for zietronix
    AFR=(float(o2Raw)*5/255)*2+9.6;


    state=Display;
    break;
    /////////////////////////////////////////////
    case(Display):
    //////////////////////////////////////////

    ////////////////////////////////////////

    switch(displayState){



      ////////////////////////////////////////////
      case(DisplayTemp):
   
      LCD.setCursor(0,0);
      LCD.print("Water Temp:");  
      LCD.print(WaterTemp);
      // LCD.print();
      LCD.print("F    ");
      progBar(map(WaterTemp,180,263,50,100),1);



      LCD.setCursor(0,2);
      LCD.print("IAT:");  
      LCD.print(IAT);
      // LCD.print();
      LCD.print("F        ");
      progBar(map(IAT,180,263,50,100),3);






      if (buttonState != lastButtonState&&buttonState==HIGH) {
        LCD.clear();

        displayState=DisplayRpmSpeed;
      }
      lastButtonState = buttonState;
      break;
      //////////////////////////////////////////////////////////////
      case(DisplayRpmSpeed):


      LCD.setCursor(0,0);
      LCD.print("RPM:");
      LCD.print(iirRpm);
      LCD.print("      ");
      progBar(map(iirRpm,0,8000,0,100),1);

      LCD.setCursor(0,2);
      LCD.print("Speed:");  
      LCD.print(Speed);
      LCD.print("MPH    ");
      progBar(map(Speed,0,100,0,100),3);


      if (buttonState != lastButtonState&&buttonState==HIGH) {

        displayState=DisplayO2;
        LCD.clear();
      }
      lastButtonState = buttonState;


      break;
      /////////////////////////////////////////////////////
      case(DisplayO2):////never actually can go to this case..... For testing

      LCD.setCursor(0,0);
      LCD.print("AFR:");
      LCD.print(AFR);
      LCD.print("      ");
      progBar(map(AFR,9.6,17,0,100),1);
      
      
      
      
      if (buttonState != lastButtonState&&buttonState==HIGH) {

        displayState=DisplayTemp;
        LCD.clear();
      }
      lastButtonState = buttonState;   
      break;
      ///////////////////////////////////////////////////////////////////

    }

    state=ADRead;


    break;
  }
  //lastTime=micros();


}



////////////////Functions/////////////////////////


void progBar(int percent,int line){

  int prog=0;
  int spaces=0;
  int clr=0; 
  prog=map(constrain(percent,0,100),0,100,0,20);

  LCD.setCursor(0,line);
  while(spaces<prog){
    LCD.print(255,BYTE);
    spaces++;
  }
  while(spaces==prog&&clr<20-spaces){
    LCD.print(" ");
    clr++;
  }

}


/////////////////////////////////////////////////////////
float calcTemp(int raw)

{

  if(raw>45)

    return -.8334*float(raw) + 194.25;

  else if(raw<=45)

    return -2.3529*float(raw) + 263.0;

}

////////////////////////////////////////////////////////
byte ecuRead(int nextState, int nextSerialState, byte ecuAddress)
{

  if (Serial.available() > 0)
  {


    state=nextState;
    serialState=nextSerialState;
    serialCount=0;
    return Serial.read();

  }
  else if (serialCount==0 || serialCount%10000==0)
  {
    Serial.print(ecuAddress,BYTE);
    // Serial.print(serialCount);
    serialCount++;

  }

  if(serialCount!=0){
    serialCount++;
    if( serialCount==100){

      LCD.clear();
      LCD.print("Connecting...");

    }

  }
}


















